
    //将视图中的需要局部刷新的部分与ViewModel用绑定处理函数连结在一起,生成updateView函数,
    //而它内部调用着之前编译好的函数compileFn，双向产生依赖，成为双向绑定链的最顶层

    //on binding相关

    function fixEvent(event) {
        var target = event.target = event.srcElement
        event.which = event.charCode != null ? event.charCode : event.keyCode
        if (/mouse|click/.test(event.type)) {
            var doc = target.ownerDocument || DOC
            var box = doc.compatMode === "BackCompat" ? doc.body : doc.documentElement
            event.pageX = event.clientX + (box.scrollLeft >> 0) - (box.clientLeft >> 0)
            event.pageY = event.clientY + (box.scrollTop >> 0) - (box.clientTop >> 0)
        }
        event.preventDefault = function() { //阻止默认行为
            event.returnValue = false
        }
        event.stopPropagation = function() { //阻止事件在DOM树中的传播
            event.cancelBubble = true
        }
        return event
    }
    //visible binding相关
    var cacheDisplay = avalon.oneObject("a,abbr,b,span,strong,em,font,i,kbd", "inline")
    avalon.mix(cacheDisplay, avalon.oneObject("div,h1,h2,h3,h4,h5,h6,section,p", "block"))

    function parseDisplay(nodeName, val) {
        //用于取得此类标签的默认display值
        nodeName = nodeName.toLowerCase()
        if (!cacheDisplay[nodeName]) {
            var node = DOC.createElement(nodeName)
            root.appendChild(node)
            if (window.getComputedStyle) {
                val = window.getComputedStyle(node, null).display
            } else {
                val = node.currentStyle.display
            }
            root.removeChild(node)
            cacheDisplay[nodeName] = val
        }
        return cacheDisplay[nodeName]
    }

    domParser.setAttribute("className", "t")
    var fuckIEAttr = domParser.className === "t"
    var propMap = {
        "class": "className",
        "for": "htmlFor"
    }
    var bindingHandlers = avalon.bindingHandlers = {
        "if": function(data, vmodels) {
            var placehoder = DOC.createComment("@")
            var parent = data.element.parentNode
            watchView(data.value, vmodels, data, function(val, elem) {

                if (val) { //添加 如果它不在DOM树中
                    if (!elem.parentNode || elem.parentNode.nodeType === 11) {
                        parent.replaceChild(elem, placehoder)
                        elem.noRemove = 0
                    }
                } else { //移除  如果它还在DOM树中
                    if (elem.parentNode && elem.parentNode.nodeType === 1) {
                        parent.replaceChild(placehoder, elem)
                        elem.noRemove = 1
                    }
                }
            })
        },
        // ms-attr-class="xxx" vm.xxx="aaa bbb ccc"将元素的className设置为aaa bbb ccc
        // ms-attr-class="xxx" vm.xxx=false  清空元素的所有类名
        // ms-attr-name="yyy"  vm.yyy="ooo" 为元素设置name属性
        "attr": function(data, vmodels) {
            data.remove = false
            watchView(data.value, vmodels, data, function(val, elem) {
                var attrName = data.node.name
                var toRemove = (val === false) || (val === null) || (val === void 0)
                if (toRemove)
                    elem.removeAttribute(attrName)
                if (fuckIEAttr && attrName in propMap) {
                    attrName = propMap[attrName]
                    if (toRemove) {
                        elem.removeAttribute(attrName)
                    } else {
                        elem[attrName] = val
                    }
                } else if (!toRemove) {
                    elem.setAttribute(attrName, val)
                }
            })
        },
        "on": function(data, vmodels) {
            var callback, type = data.args[0],
                    elem = data.element
            watchView(data.value, vmodels, data, function(fn) {
                callback = fn
            })
            if (!elem.$vmodels) {
                elem.$vmodel = elem.$scope = vmodels[0]
                elem.$vmodels = vmodels
            }
            if (type && typeof callback === "function") {
                avalon.bind(elem, type, callback)
            }
        },
        "data": function(data, vmodels) {
            watchView(data.value, vmodels, data, function(val, elem) {
                var key = "data-" + data.args.join("-")
                elem.setAttribute(key, val)
            })
        },
        //抽取innerText中插入表达式，置换成真实数据放在它原来的位置
        //<div>{{firstName}} + java</div>，如果model.firstName为ruby， 那么变成
        //<div>ruby + java</div>
        "text": function(data, vmodels) {
            watchView(data.value, vmodels, data, function(val) {
                data.node.nodeValue = val
            })
        },
        //控制元素显示或隐藏
        "visible": function(data, vmodels) {
            var elem = data.element
            var display = avalon(elem).css("display")
            display = display === "none" ? parseDisplay(elem.tagName) : display
            watchView(data.value, vmodels, data, function(val) {
                elem.style.display = val ? display : "none"
            })
        },
        //这是一个字符串属性绑定的范本, 方便你在title, alt,  src, href, include, css添加插值表达式
        //<a ms-href="{{url.hostname}}/{{url.pathname}}.html">
        "href": function(data, vmodels) {
            var text = data.value.trim()
            var simple = true
            var name = data.type
            if (text.indexOf(openTag) > -1 && text.indexOf(closeTag) > 2) {
                simple = false
                if (rexpr.test(text) && RegExp.rightContext == "") {
                    simple = true
                    text = RegExp.$1
                }
            }
            watchView(text, vmodels, data, function(val, elem) {
                if (name === "css") {
                    avalon(elem).css(data.args.join("-"), val)
                } else if (name == "include") {
                    if (data.args + "" === "src") {
                        var ajax = new (window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP")
                        ajax.onreadystatechange = function() {
                            if (ajax.readyState == 4) {
                                var s = ajax.status
                                if (s >= 200 && s < 300 || s === 304 || s === 1223) {
                                    elem.innerHTML = ajax.responseText
                                    avalon.scan(elem, vmodels)
                                }
                            }
                        }
                        ajax.open("GET", val, true);
                        ajax.send(null);
                    } else {
                        var el = DOC.getElementById(val)
                        avalon.nextTick(function() {
                            elem.innerHTML = el && el.innerHTML;
                            avalon.scan(elem, vmodels)
                        })
                    }
                } else {
                    elem[name] = val
                }
            }, simple ? null : scanExpr(data.value))
        },
        //这是一个布尔属性绑定的范本，布尔属性插值要求整个都是一个插值表达式，用{{}}包起来
        //布尔属性在IE下无法取得原来的字符串值，变成一个布尔，因此需要用ng-disabled
        "disabled": function(data, vmodels) {
            var name = data.type,
                    propName = name === "readonly" ? "readOnly" : name
            watchView(data.value, vmodels, data, function(val, elem) {
                elem[propName] = !!val
            })
        },
        //ms-bind-name="callback",绑定一个属性，当属性变化时执行对应的回调，this为绑定元素
        "bind": function(data, vmodels) {
            var fn = data.value.trim(),
                    name = data.args[0]
            for (var i = 0, vm; vm = vmodels[i++]; ) {
                if (vm.hasOwnProperty(fn)) {
                    fn = vm[fn]
                    break
                }
            }
            if (typeof fn === "function") {
                vm.$watch(name, function(neo, old) {
                    fn.call(data.element, neo, old)
                })
            }
        },
        //根据VM的属性值或表达式的值切换类名，ms-class-xxx="flag" 
        //http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html
        "class": function(data, vmodels) {
            watchView(data.value, vmodels, data, function(val, elem) {
                var cls = data.args.join("-")
                if (typeof val === "function") {
                    if (!elem.$vmodels) {
                        elem.$vmodel = elem.$scope = vmodels[0]
                        elem.$vmodels = vmodels
                    }
                    val = val.call(elem)
                }
                avalon(elem).toggleClass(cls, !!val)
            })
        },
        //在移出移入时切换类名
        "hover": function(data) {
            var god = avalon(data.element)
            god.bind("mouseenter", function() {
                god.addClass(data.value)
            })
            god.bind("mouseleave", function() {
                god.removeClass(data.value)
            })
        },
        //在聚焦失焦中切换类名
        "active": function(data) {
            var elem = data.element
            var god = avalon(elem)
            elem.tabIndex = elem.tabIndex || -1
            god.bind("focus", function() {
                god.addClass(data.value)
            })
            god.bind("blur", function() {
                god.removeClass(data.value)
            })
        },
        "html": function(data, vmodels) {
            watchView(data.value, vmodels, data, function(val, elem) {
                val = val == null ? "" : val + ""
                if (data.replaceNodes) {
                    domParser.innerHTML = val
                    var replaceNodes = []
                    while (domParser.firstChild) {
                        replaceNodes.push(domParser.firstChild)
                        documentFragment.appendChild(domParser.firstChild)
                    }
                    elem.insertBefore(documentFragment, data.replaceNodes[0]);
                    for (var i = 0, node; node = data.replaceNodes[i++]; ) {
                        elem.removeChild(node)
                    }
                    data.replaceNodes = replaceNodes

                } else {
                    elem.innerHTML = val
                }
            })
        },
        "ui": function(data, vmodels, opts) {
            var uiName = data.value.trim() //此UI的名字
            if (typeof avalon.ui[uiName] === "function") {
                var id = (avalon(data.element).data("id") || "").trim()
                id = id || uiName + setTimeout("1") //ViewModel的$id
                data.element.setAttribute(prefix + "controller", id)
                var optsName = data.args[0] //它的参数对象
                if (optsName) {
                    for (var i = 0, scope; scope = vmodels[i++]; ) {
                        if (scope.hasOwnProperty(optsName)) {
                            opts = scope[optsName]
                            break
                        }
                    }
                    if (!opts) {
                        for (var i in VMODELS) {
                            scope = VMODELS[i]
                            if (scope.hasOwnProperty(optsName)) {
                                opts = scope[optsName]
                                break
                            }
                        }
                    }
                }

                avalon.ui[uiName](data.element, id, opts)
            }
        }
    }
    